// public/sw-upload.js
let uploadTasks = new Map(); // 内存中临时存储上传任务（SW 运行时有效）
let db; // IndexedDB 实例

// 1. 初始化 IndexedDB：存储上传进度（文件ID → 任务状态）
const initIndexedDB = () => {
  return new Promise((resolve, reject) => {
    // 打开数据库（名称：uploadDB，版本：1）
    const request = indexedDB.open('uploadDB', 1);

    // 数据库升级/首次创建时，创建存储对象（表：uploadTasks）
    request.onupgradeneeded = (e) => {
      db = e.target.result;
      // 创建表：以 fileId（文件MD5）为主键
      if (!db.objectStoreNames.contains('uploadTasks')) {
        db.createObjectStore('uploadTasks', { keyPath: 'fileId' });
      }
    };

    // 打开成功
    request.onsuccess = (e) => {
      db = e.target.result;
      resolve(db);
    };

    // 打开失败
    request.onerror = (e) => {
      reject(`IndexedDB 初始化失败：${e.target.error}`);
    };
  });
};

// 2. 从 IndexedDB 加载未完成的上传任务（SW 激活时执行）
const loadUnfinishedTasks = async () => {
  await initIndexedDB();
  const transaction = db.transaction('uploadTasks', 'readonly');
  const store = transaction.objectStore('uploadTasks');
  const request = store.openCursor(); // 遍历所有未完成任务

  return new Promise((resolve) => {
    request.onsuccess = (e) => {
      const cursor = e.target.result;
      if (cursor) {
        const task = cursor.value;
        if (!task.finished) { // 只加载未完成的任务
          uploadTasks.set(task.fileId, task);
        }
        cursor.continue();
      } else {
        resolve(uploadTasks);
      }
    };
  });
};

// 3. 保存上传任务到 IndexedDB
const saveTaskToDB = (task) => {
  if (!db) return Promise.reject('IndexedDB 未初始化');
  const transaction = db.transaction('uploadTasks', 'readwrite');
  const store = transaction.objectStore('uploadTasks');
  store.put(task); // 存在则更新，不存在则新增
  return new Promise((resolve) => transaction.oncomplete = resolve);
};

// 4. 移除已完成的任务（上传成功/取消后）
const removeTaskFromDB = (fileId) => {
  if (!db) return Promise.reject('IndexedDB 未初始化');
  const transaction = db.transaction('uploadTasks', 'readwrite');
  const store = transaction.objectStore('uploadTasks');
  store.delete(fileId);
  return new Promise((resolve) => transaction.oncomplete = resolve);
};

// 5. 核心：接管上传请求（拦截分片上传的 PUT 请求）
const handleUploadRequest = async (event) => {
  const request = event.request;
  const url = new URL(request.url);

  // 只拦截分片上传的 PUT 请求（根据你的预签名URL路径判断，比如包含 "upload_part"）
  // 替换成你实际的分片上传URL特征（如 preSignUploadUrl 返回的URL）
  if (request.method === 'PUT' && url.pathname.includes('upload_part')) {
    event.respondWith(
      (async () => {
        // 从请求中解析文件ID（假设预签名URL中包含 fileId 参数）
        const fileId = url.searchParams.get('fileId');
        const partNumber = url.searchParams.get('partNumber');
        const task = uploadTasks.get(fileId);

        if (!task) return fetch(request); // 无任务信息，走默认请求

        try {
          // 执行上传请求
          const response = await fetch(request);
          if (response.ok) {
            // 标记该分片已上传
            task.uploadedParts.add(partNumber);
            // 计算进度
            task.progress = Math.ceil((task.uploadedParts.size / task.totalParts) * 100);
            // 保存进度到 IndexedDB
            await saveTaskToDB(task);
            // 向主线程发送进度更新（如果页面还在）
            self.clients.matchAll().then((clients) => {
              clients.forEach((client) => {
                client.postMessage({
                  type: 'UPLOAD_PROGRESS',
                  data: { fileId, progress: task.progress, partNumber }
                });
              });
            });

            // 所有分片上传完成：标记任务完成，清理DB
            if (task.uploadedParts.size === task.totalParts) {
              task.finished = true;
              await saveTaskToDB(task);
              await removeTaskFromDB(fileId);
              uploadTasks.delete(fileId);
              // 通知主线程上传完成
              self.clients.matchAll().then((clients) => {
                clients.forEach((client) => {
                  client.postMessage({
                    type: 'UPLOAD_FINISHED',
                    data: { fileId, fileName: task.fileName }
                  });
                });
              });
            }
          }
          return response;
        } catch (error) {
          // 上传失败：通知主线程
          self.clients.matchAll().then((clients) => {
            clients.forEach((client) => {
              client.postMessage({
                type: 'UPLOAD_ERROR',
                data: { fileId, error: error.message, partNumber }
              });
            });
          });
          throw error;
        }
      })()
    );
  }
};

// 6. 监听主线程消息（接收上传任务、取消上传等）
self.addEventListener('message', async (event) => {
  const { type, data } = event.data;
  const client = event.source; // 主线程客户端

  switch (type) {
    // 主线程发送「新增上传任务」
    case 'ADD_UPLOAD_TASK': {
      const { fileId, fileName, totalParts, chunkSize, preSignUrls } = data;
      // 构建任务对象
      const task = {
        fileId, // 文件唯一标识（MD5）
        fileName,
        totalParts, // 总分片数
        chunkSize,
        preSignUrls, // 所有分片的预签名URL
        uploadedParts: new Set(), // 已上传分片（初始为空）
        progress: 0,
        finished: false,
        startTime: Date.now()
      };
      // 存储任务到内存和DB
      uploadTasks.set(fileId, task);
      await saveTaskToDB(task);
      // 通知主线程任务已注册
      client.postMessage({ type: 'TASK_REGISTERED', data: { fileId } });
      break;
    }

    // 主线程请求「继续未完成任务」
    case 'RESUME_UNFINISHED_TASKS': {
      const tasks = Array.from(uploadTasks.values()).filter(t => !t.finished);
      client.postMessage({ type: 'UNFINISHED_TASKS', data: { tasks } });
      break;
    }

    // 主线程发送「取消上传」
    case 'CANCEL_UPLOAD': {
      const { fileId } = data;
      const task = uploadTasks.get(fileId);
      if (task) {
        uploadTasks.delete(fileId);
        await removeTaskFromDB(fileId);
      }
      client.postMessage({ type: 'UPLOAD_CANCELED', data: { fileId } });
      break;
    }
  }
});

// 7. SW 生命周期：安装（缓存必要资源）
self.addEventListener('install', (event) => {
  // 跳过等待，直接激活新 SW（避免旧 SW 干扰）
  self.skipWaiting();
  // 安装时初始化 DB
  event.waitUntil(initIndexedDB());
});

// 8. SW 生命周期：激活（接管所有客户端，加载未完成任务）
self.addEventListener('activate', (event) => {
  // 让 SW 控制所有已打开的页面
  event.waitUntil(
    self.clients.claim()
      .then(loadUnfinishedTasks()) // 加载未完成的上传任务
  );
});

// 9. 拦截所有 fetch 请求（只处理上传相关）
self.addEventListener('fetch', (event) => {
  handleUploadRequest(event);
});